home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / INTERNET / SITES / GRAHAM / XA_6S.ZIP / SOURCE / OBJECTS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-08  |  17.5 KB  |  689 lines

  1. /*
  2.  * XaAES - XaAES Ain't the AES
  3.  *
  4.  * A multitasking AES replacement for MiNT
  5.  *
  6.  */
  7.  
  8. #include <stdlib.h>
  9. #include <osbind.h>
  10. #ifdef LATTICE
  11. #undef abs        /* MiNTlib (PL46) #define is buggy! */
  12. #define abs(i)    __builtin_abs(i)
  13. #endif
  14. #include "XA_DEFS.H"
  15. #include "XA_TYPES.H"
  16. #include "XA_GLOBL.H"
  17. #include "K_DEFS.H"
  18. #include "RECTLIST.H"
  19. #include "BOX3D.H"
  20. #include "objects.h"
  21. #include "objects.src/box.h"
  22. #include "objects.src/boxchar.h"
  23. #include "objects.src/boxtext.h"
  24. #include "objects.src/button.h"
  25. #include "objects.src/cicon.h"
  26. #include "objects.src/ftext.h"
  27. #include "objects.src/fboxtext.h"
  28. #include "objects.src/ibox.h"
  29. #include "objects.src/icon.h"
  30. #include "objects.src/image.h"
  31. #include "objects.src/progdef.h"
  32. #include "objects.src/slist.h"
  33. #include "objects.src/string.h"
  34. #include "objects.src/text.h"
  35.  
  36. /*
  37.     OBJECT TREE ROUTINES
  38.     - new version of the object display routine modularises the whole system.
  39. */
  40.  
  41.  
  42. ObjectDisplayCallback objc_jump_table[G_MAX];
  43.  
  44. #if 0
  45. void my_draw_2d_box(short x, short y, short w, short h, short border_thick, short colour)
  46. {
  47.     short coords[10];
  48.     short x2,y2;
  49.  
  50.     if ( border_thick<0 )    /* outside border */
  51.     {
  52.         border_thick = -border_thick;
  53.         x -= border_thick;
  54.         y -= border_thick;
  55.         w += 2*border_thick;
  56.         h += 2*border_thick;
  57.     }
  58.  
  59.     vsl_color(V_handle, colour);
  60.  
  61.     x2=x+w-1;
  62.     y2=y+h-1;
  63.     do {
  64.         coords[0]=coords[6]=coords[8]=x++;
  65.         coords[1]=coords[3]=coords[9]=y++;
  66.         coords[2]=coords[4]=x2--;
  67.         coords[5]=coords[7]=y2--;
  68.         v_pline(V_handle, 5, coords);
  69.     } while (--border_thick);
  70. }
  71. #endif
  72.  
  73. const short selected_colour[]={1,0,13,15,14,10,12,11,8,9,5,7,6,2,4,3};
  74. const short selected3D_colour[]={1,0,13,15,14,10,12,11,9,8,5,7,6,2,4,3};
  75.  
  76. short global_clip[4];    /* Bloody progdefs need to know the clip rectangle */
  77.  
  78. void set_clip(short x, short y, short w, short h)
  79. {
  80.     global_clip[0]=x;
  81.     global_clip[1]=y;
  82.     global_clip[2]=x+w-1;
  83.     global_clip[3]=y+h-1;
  84.     vs_clip(V_handle,1,global_clip);
  85. }
  86.  
  87. /* Set clipping to entire screen */
  88. void clear_clip(void)
  89. {
  90.     global_clip[0]=display.x;
  91.     global_clip[1]=display.y;
  92.     global_clip[2]=display.x+display.w-1;
  93.     global_clip[3]=display.y+display.h-1;
  94.     vs_clip(V_handle,1,global_clip);
  95. }
  96.  
  97. /*
  98.     Draw a 2d box outline (allows 'proper' thickness - 1,2,3,etc)
  99.     Note: expects writing mode to be set up by caller.
  100. */
  101. void draw_2d_box(short x, short y, short w, short h, short border_thick, short colour)
  102. {
  103.     short coords[4];
  104.     short vo;
  105.     
  106.     if (border_thick<0)
  107.     {
  108.         border_thick++;
  109.         vo=-border_thick-1;
  110.     }else{
  111.         border_thick--;
  112.         vo=border_thick+1;
  113.     }
  114.  
  115.     if (border_thick>5)
  116.         border_thick=0;
  117.  
  118.     vsf_interior(V_handle, FIS_SOLID);
  119.     vsf_color(V_handle, colour);
  120.             
  121.     coords[0]=x;
  122.     coords[1]=y-vo;
  123.     coords[2]=x+border_thick;
  124.     coords[3]=y+h+vo;
  125.     v_bar(V_handle, coords);
  126.     coords[0]=x+w;
  127.     coords[1]=y-vo;
  128.     coords[2]=x+w-border_thick;
  129.     coords[3]=y+h+vo;
  130.     v_bar(V_handle, coords);
  131.     coords[0]=x;
  132.     coords[1]=y;
  133.     coords[2]=x+w;
  134.     coords[3]=y+border_thick;
  135.     v_bar(V_handle, coords);
  136.     coords[0]=x;
  137.     coords[1]=y+h;
  138.     coords[2]=x+w;
  139.     coords[3]=y+h-border_thick;
  140.     v_bar(V_handle, coords);
  141.  
  142. }
  143.  
  144. #if 0
  145. #define draw_2d_box(x,y,w,h,t,c)    if ( (Kbshift(-1)&3)==0 ) \
  146.     my_draw_2d_box(x,y,w,h,t,c) ; else draw_2d_box(x,y,w,h,t,c)
  147. #endif
  148.  
  149. /*
  150.     Format a G_FTEXT type text string from it's template,
  151.     and return the real position of the text cursor in this
  152. */
  153. short format_dialog_text(char *text_out, char *template, char *text_in,short edit_pos)
  154. {
  155.     short index=0,edit_index,tpos=0;
  156.     
  157.     while(*template)
  158.     {
  159.         switch(*template)
  160.         {
  161.             case '_':                /* Found text field */
  162.                 if (tpos==edit_pos)
  163.                     edit_index=index;
  164.                 
  165.                 if (*text_in)
  166.                 {
  167.                     *text_out=*text_in;
  168.                     text_in++;
  169.                 }else{
  170.                     *text_out='_';
  171.                 }
  172.                 tpos++;
  173.                 
  174.                 text_out++;
  175.                 template++;
  176.                 break;
  177.             default:                /* Formatting characters */
  178.                 *text_out=*template;
  179.                 text_out++;
  180.                 template++;
  181.                 break;
  182.         }
  183.         index++;
  184.     }
  185.     *text_out='\0';
  186.     
  187.     return edit_index;
  188. }
  189.  
  190. void shadow_object(OBJECT *ob, short parent_x, short parent_y, OBJC_COLORWORD *colourword, short border_thick)
  191. {
  192.     short coords[4];
  193.     short offset, increase;
  194.     
  195.     /*    Are we shadowing this object? (Borderless objects aren't shadowed!) */
  196.     if (border_thick && (ob->ob_state&SHADOWED))
  197.     {
  198.  
  199.         if (border_thick>0)
  200.             { offset=border_thick ; increase=border_thick-1 ; }
  201.         else
  202.             { offset=0 ; increase=-3*border_thick-1 ; }
  203.  
  204.         vsf_color(V_handle,colourword->borderc);
  205.         vsf_interior(V_handle, FIS_SOLID);
  206.         coords[0]=parent_x+ob->ob_x+offset;
  207.         coords[1]=parent_y+ob->ob_y+offset;
  208.         coords[2]=coords[0]+ob->ob_width+increase;
  209.         coords[3]=coords[1]+ob->ob_height+increase;
  210.         v_bar(V_handle, coords);
  211.     }
  212. }
  213.  
  214. void set_colours(OBJECT *ob, OBJC_COLORWORD *colourword)
  215. {
  216.     short colourmode=(display.colours>=16) ;
  217.     
  218.     /* Note: `colourword->opaque' applies *only* to the text
  219.         part of an object!!!!!! */
  220.     vswr_mode(V_handle, MD_REPLACE);
  221.  
  222.     vsf_interior(V_handle, FIS_PATTERN);
  223.     if (colourword->pattern==7)
  224.     {
  225.         vsf_style(V_handle, 8);
  226.     }else{
  227.         if (colourword->pattern==0)
  228.         {
  229.             vsf_style(V_handle, 8);
  230.             if ((colourword->fillc==0)&&(ob->ob_flags&FLD3DANY))    /* Object inherits default dialog background colour? */
  231.             {
  232.                 vswr_mode(V_handle, MD_TRANS);
  233.                 colourword->fillc=display.dial_colours.bg_col;
  234.             }else{
  235.                 colourword->fillc=WHITE;
  236.             }
  237.         }else{
  238.             vsf_style(V_handle, colourword->pattern);
  239.         }
  240.     }
  241.  
  242.     if (colourmode && (ob->ob_state&SELECTED))
  243.     {
  244.         if (ob->ob_flags&FLD3DANY)        /* Allow a different colour set for 3d push  */
  245.             vsf_color(V_handle, selected3D_colour[colourword->fillc]);
  246.         else
  247.             vsf_color(V_handle, selected_colour[colourword->fillc]);
  248.     }else{
  249.         vsf_color(V_handle, colourword->fillc);
  250.     }
  251.     vst_color(V_handle, colourword->textc);
  252.     
  253.     vsf_perimeter(V_handle, 0);
  254. }
  255.  
  256. GRECT set_text(OBJECT *ob, OBJC_COLORWORD *colourword, short *border_thick, short parent_x, short parent_y)
  257. {
  258.     TEDINFO *textblk=(TEDINFO*)ob->ob_spec;
  259.     GRECT rtn;
  260.     short temp;
  261.     unsigned short *t=(unsigned short*)colourword;
  262.     
  263.     *t=(unsigned short)textblk->te_color;
  264.     
  265.     *border_thick=textblk->te_thickness;
  266.  
  267.     if (ob->ob_state&IS_EDIT)
  268.         rtn.g_x=textblk->te_tmplen;
  269.     else
  270.         rtn.g_x=0;
  271.             
  272.     switch(textblk->te_just)            /*Set text alignment - why on earth did */
  273.     {                                    /* atari use a different horizontal alignment */
  274.         case 0:                            /* code for GEM to the one the VDI uses? */
  275.             vst_alignment(V_handle,0,5,&temp,&temp);
  276.             break;
  277.         case 1:
  278.             vst_alignment(V_handle,2,5,&temp,&temp);
  279.             break;
  280.         case 2:
  281.             vst_alignment(V_handle,1,5,&temp,&temp);
  282.             break;
  283.     }
  284.             
  285.     switch(textblk->te_font)    /* Set the correct text size & font */
  286.     {
  287.         case TE_GDOS_PROP:        /* Use a proportional SPEEDOGDOS font (AES4.1 style) */
  288.         case TE_GDOS_MONO:        /* Use a monospaced SPEEDOGDOS font (AES4.1 style) */
  289.         case TE_GDOS_BITM:        /* Use a GDOS bitmap font (AES4.1 style) */
  290.             vst_font(V_handle,textblk->te_fontid);
  291.             vst_point(V_handle,textblk->te_fontsize,&temp,&temp,&temp,&temp);
  292.             rtn.g_w=display.c_max_w;
  293.             rtn.g_h=display.c_max_h;
  294.             rtn.g_y=parent_y + ob->ob_y + ((ob->ob_height-display.c_max_h)/2);
  295.             break;
  296.         case TE_STANDARD:        /* Use the standard system font (probably 10 point) */
  297.             vst_font(V_handle,display.standard_font_id);
  298.             vst_point(V_handle,display.standard_font_point,&temp,&temp,&temp,&temp);
  299.             rtn.g_w=display.c_max_w;
  300.             rtn.g_h=display.c_max_h;
  301.             rtn.g_y=parent_y + ob->ob_y + ((ob->ob_height-display.c_max_h)/2);
  302.             break;
  303.         case TE_SMALL:            /* Use the small syatem font (probably 8 point) */
  304.             vst_font(V_handle,display.small_font_id);
  305.             vst_point(V_handle,display.small_font_point,&temp,&temp,&temp,&temp);
  306.             rtn.g_w=display.c_min_w;
  307.             rtn.g_h=display.c_min_h;
  308.             rtn.g_y=parent_y + ob->ob_y + ((ob->ob_height-display.c_min_h)/2);
  309.             break;
  310.     }
  311.     
  312.     return rtn;
  313. }
  314.  
  315. void d_g_title(ODC_PARM *odc_p)
  316. {
  317. }
  318.  
  319. /*
  320.     Initialise the object display jump table
  321. */
  322. void init_objects(void)
  323. {
  324.     short f;
  325.  
  326.     for(f=0; f<G_MAX; f++)
  327.         objc_jump_table[f]=NULL;            /* Anything with a NULL pointer won't get called */
  328.     
  329.     objc_jump_table[G_BOX]=&d_g_box;
  330.     objc_jump_table[G_TEXT]=&d_g_text;
  331.     objc_jump_table[G_BOXTEXT]=&d_g_boxtext;
  332.     objc_jump_table[G_IMAGE]=&d_g_image;
  333.     objc_jump_table[G_PROGDEF]=&d_g_progdef;
  334.     objc_jump_table[G_IBOX]=&d_g_ibox;
  335.     objc_jump_table[G_BUTTON]=&d_g_button;
  336.     objc_jump_table[G_BOXCHAR]=&d_g_boxchar;
  337.     objc_jump_table[G_STRING]=&d_g_string;
  338.     objc_jump_table[G_FTEXT]=&d_g_ftext;
  339.     objc_jump_table[G_FBOXTEXT]=&d_g_fboxtext;
  340.     objc_jump_table[G_ICON]=&d_g_icon;
  341.     objc_jump_table[G_TITLE]=&d_g_title;
  342.     objc_jump_table[G_CICON]=&d_g_cicon;
  343.     objc_jump_table[G_SLIST]=&d_g_slist;
  344.     
  345. }
  346.  
  347. /*
  348.     Display a primitive object
  349. */
  350. void display_object(OBJECT *tree,short object,short parent_x,short parent_y)
  351. {
  352.     OBJC_COLORWORD *colourword;
  353.     OBJECT *ob=tree+object;
  354.     ObjectDisplayCallback display_routine;
  355.     ODC_PARM odc_p;
  356.     unsigned short zap;
  357.     short border_thick=0,coords[10];
  358.     short temp;
  359.     short colourmode=(display.colours>=16) ;
  360.     short state_mask=(SELECTED|CROSSED|CHECKED|DISABLED); /* -> G_PROGDEF */
  361.     short obx=parent_x+ob->ob_x;
  362.     short oby=parent_y+ob->ob_y;
  363.     short obx2=obx+ob->ob_width-1;
  364.     short oby2=oby+ob->ob_height-1;
  365.     short t;
  366.  
  367.     if ((obx>global_clip[2])            /* Exit immediately if object is totally outside clip area */
  368.         ||((obx2<global_clip[0])
  369.         ||((oby>global_clip[3])
  370.         ||(oby2<global_clip[1]))))
  371.     {
  372.         return;
  373.     }
  374.  
  375.     t=ob->ob_type&0xff;
  376.     colourword=(OBJC_COLORWORD*)&zap;
  377.  
  378.     if ((ob->ob_flags&DEFAULT) &&    /* Default exit object */
  379.         (t==G_BUTTON) &&            /* Only BUTTONS change appearance! */
  380.         (ob->ob_flags&FLD3DANY))    /* 2D buttons are handled elsewhere */
  381.     {
  382.         vsf_color(V_handle,BLACK);
  383.         vsf_interior(V_handle, FIS_SOLID);
  384.         coords[0]=parent_x+ob->ob_x-2;
  385.         coords[1]=parent_y+ob->ob_y-2;
  386.         coords[2]=coords[0]+ob->ob_width+3;
  387.         coords[3]=coords[1]+ob->ob_height+3;
  388.         v_bar(V_handle, coords);
  389.     }
  390.  
  391.     display_routine=objc_jump_table[t];    /* Get display routine for this type of object from jump table */
  392.  
  393.     if (display_routine==NULL)            /* If we don't have a display routine for a given object type, draw a box instead */
  394.         display_routine=objc_jump_table[G_IBOX];
  395.  
  396.     odc_p.tree=tree;                    /* fill in the object display parameter structure */
  397.     odc_p.object=object;                    
  398.     odc_p.parent_x=parent_x;
  399.     odc_p.parent_y=parent_y;
  400.     odc_p.state_mask=&state_mask;
  401.  
  402.     (*display_routine)(&odc_p);            /* call the appropriate display routine */
  403.  
  404.     if (ob->ob_state&CROSSED)
  405.     {
  406.         vsl_color(V_handle,colourword->borderc);
  407.         coords[0]=parent_x+ob->ob_x;
  408.         coords[1]=parent_y+ob->ob_y;
  409.         coords[2]=parent_x+ob->ob_x+ob->ob_width-1;
  410.         coords[3]=parent_y+ob->ob_y+ob->ob_height-1;
  411.         v_pline(V_handle,2,coords);
  412.         coords[0]=parent_x+ob->ob_x+ob->ob_width-1;
  413.         coords[2]=parent_x+ob->ob_x;
  414.         v_pline(V_handle,2,coords);
  415.     }
  416.     
  417.     /* Handle CHECKED object state: */
  418.     if ( ob->ob_state & state_mask & CHECKED )
  419.     {
  420.         vst_font(V_handle,display.standard_font_id);
  421.         vst_point(V_handle,display.standard_font_point,&temp,&temp,&temp,&temp);
  422.         vswr_mode(V_handle, MD_TRANS);
  423.         vst_alignment(V_handle,0,5,&temp,&temp);
  424.         vst_color(V_handle, BLACK);
  425.         v_gtext(V_handle, obx+2, oby, "\10");    /* ASCII 8 = checkmark */
  426.     }
  427.  
  428.     /* Handle CROSSED object state: */
  429.     if ( ob->ob_state & state_mask & CROSSED )
  430.     {
  431.         coords[0]=coords[4]=obx-border_thick;
  432.         coords[1]=coords[7]=oby-border_thick;
  433.         coords[2]=coords[6]=obx2+border_thick;
  434.         coords[3]=coords[5]=oby2+border_thick;
  435.  
  436.         vswr_mode(V_handle, MD_TRANS);
  437.         vsl_color(V_handle, WHITE);
  438.         vsl_width(V_handle, 1);
  439.         vsl_type(V_handle, 1);
  440.         v_pline(V_handle, 2, &coords[0]);
  441.         v_pline(V_handle, 2, &coords[4]);
  442.     }
  443.  
  444.     coords[0]=obx;
  445.     coords[1]=oby;
  446.     coords[2]=obx2;
  447.     coords[3]=oby2;
  448.     if (border_thick > 0)        /* Inside border */
  449.     {
  450.         coords[0]+=border_thick;
  451.         coords[1]+=border_thick;
  452.         coords[2]-=border_thick;
  453.         coords[3]-=border_thick;
  454.     }
  455.  
  456.     /* Handle DISABLED state: */
  457.     /* (May not look too hot in colour mode, but it's better than
  458.         no disabling at all...) */
  459.     if ( ob->ob_state & state_mask & DISABLED )
  460.     {
  461.         static short pattern[16]={
  462.             0x5555, 0xaaaa, 0x5555, 0xaaaa,
  463.             0x5555, 0xaaaa, 0x5555, 0xaaaa,
  464.             0x5555, 0xaaaa, 0x5555, 0xaaaa,
  465.             0x5555, 0xaaaa, 0x5555, 0xaaaa };
  466.  
  467.         vswr_mode(V_handle, MD_TRANS);
  468.         vsf_color(V_handle, WHITE);
  469.         vsf_udpat(V_handle, pattern, 1);
  470.         vsf_interior(V_handle, FIS_USER);
  471.         vr_recfl(V_handle, coords);
  472.     }
  473.  
  474.     /* Handle SELECTED state only in non-colour mode: */
  475.     if (!colourmode && ((ob->ob_state&state_mask)&SELECTED))
  476.     {
  477.         vswr_mode(V_handle, MD_XOR);
  478.         vsf_color(V_handle, BLACK);
  479.         vsf_interior(V_handle, FIS_SOLID);
  480.         vr_recfl(V_handle, coords);
  481.     }
  482.  
  483.     vswr_mode(V_handle,MD_TRANS);
  484. }
  485.  
  486.  
  487. /*
  488.     Walk an object tree, calling display for each object
  489. */
  490. short draw_object_tree(OBJECT *tree, short object, short depth)
  491. {
  492.     short next;
  493.     short current=0,rel_depth=1,head;
  494.     short x=0,y=0,start_drawing=FALSE;
  495.     
  496.     depth++;
  497.     
  498.     do {
  499.         
  500.         if (current==object)
  501.         {
  502.             start_drawing=TRUE;
  503.             rel_depth=0;
  504.         }
  505.         
  506.         if ((start_drawing)&&(!(tree[current].ob_flags&HIDETREE)))
  507.         {
  508.             display_object(tree,current,x,y);    /* Display this object */
  509.         }
  510.  
  511.         head=tree[current].ob_head;
  512.                                         /* Any non-hidden children? */
  513.         if (((head!=-1)&&(!(tree[current].ob_flags&HIDETREE)))
  514.             &&((!start_drawing)||((start_drawing)&&(rel_depth<depth))))
  515.         {
  516.         
  517.             x+=tree[current].ob_x; y+=tree[current].ob_y;
  518.             rel_depth++;
  519.             current=head;
  520.         
  521.         }else{
  522.  
  523.             next=tree[current].ob_next;        /* Try for a sibling */
  524.     
  525.             while((next!=-1)                /* Trace back up tree if no more siblings */
  526.                     &&(tree[next].ob_tail==current))
  527.             {
  528.                 current=next;
  529.                 x-=tree[current].ob_x;
  530.                 y-=tree[current].ob_y;
  531.                 next=tree[current].ob_next;
  532.                 rel_depth--;
  533.             }
  534.             current=next;
  535.         }
  536.     
  537.     }while((current!=-1)&&(!((start_drawing)&&(rel_depth<1))));
  538.  
  539.     vst_alignment(V_handle,0,5,&x,&x);
  540.     vswr_mode(V_handle, MD_TRANS);
  541.     vst_font(V_handle,display.standard_font_id);
  542.     vst_point(V_handle,display.standard_font_point,&next,&next,&next,&next);
  543.     vsf_interior(V_handle, FIS_SOLID);
  544.  
  545.     return TRUE;
  546. }
  547.  
  548. /*
  549.     Get the true screen coords of an object
  550. */
  551. short object_abs_coords(OBJECT *tree, short object, short *obx, short *oby)
  552. {
  553.     short next;
  554.     short current=0;
  555.     short x=0,y=0;
  556.     
  557.     do {
  558.         if (current==object)    /* Found the object in the tree? cool, return the coords */
  559.         {
  560.             *obx=x+tree[current].ob_x;
  561.             *oby=y+tree[current].ob_y;
  562.             return 1;
  563.         }
  564.         
  565.         if (tree[current].ob_head!=-1)        /* Any children? */
  566.         {
  567.             x+=tree[current].ob_x; y+=tree[current].ob_y;
  568.             current=tree[current].ob_head;
  569.         }else{
  570.             next=tree[current].ob_next;                            /* Try for a sibling */
  571.  
  572.             while((next!=-1)&&(tree[next].ob_tail==current))    /* Trace back up tree if no more siblings */
  573.             {
  574.                 current=next;
  575.                 x-=tree[current].ob_x;
  576.                 y-=tree[current].ob_y;
  577.                 next=tree[current].ob_next;
  578.             }
  579.             current=next;
  580.         }
  581.     } while(current!=-1);        /* If 'current' is -1 then we have finished */
  582.  
  583.     return 0;    /* Bummer - didn't find the object, so return error */
  584. }
  585.  
  586. /*
  587.     Find which object is at a given location
  588. */
  589. short find_object(OBJECT *tree, short object, short depth, short obx, short oby)
  590. {
  591.     short next;
  592.     short current=0,rel_depth=1;
  593.     short x=0,y=0,start_checking=FALSE;
  594.     short pos_object=-1;
  595.     
  596.     do {
  597.         if (current==object)    /* We can start considering objects at this point */
  598.         {
  599.             start_checking=TRUE;
  600.             rel_depth=0;
  601.         }
  602.         
  603.         if (start_checking)
  604.         {
  605.             if ((tree[current].ob_x+x<=obx)
  606.                 &&((tree[current].ob_y+y<=oby)
  607.                 &&((tree[current].ob_x+x+tree[current].ob_width>=obx)
  608.                 &&(tree[current].ob_y+y+tree[current].ob_height>=oby))))
  609.             {
  610.                 pos_object=current;    /* This is only a possible object, as it may have children on top of it. */
  611.             }
  612.         }
  613.  
  614.         if (((!start_checking)||(rel_depth<depth))&&(tree[current].ob_head!=-1))        /* Any children? */
  615.         {
  616.             x+=tree[current].ob_x; y+=tree[current].ob_y;
  617.             rel_depth++;
  618.             current=tree[current].ob_head;
  619.         }else{
  620.             next=tree[current].ob_next;                            /* Try for a sibling */
  621.  
  622.             while((next!=-1)&&(tree[next].ob_tail==current))    /* Trace back up tree if no more siblings */
  623.             {
  624.                 current=next;
  625.                 x-=tree[current].ob_x;
  626.                 y-=tree[current].ob_y;
  627.                 next=tree[current].ob_next;
  628.                 rel_depth--;
  629.             }
  630.             current=next;
  631.         }
  632.         
  633.     } while((current!=-1)&&(rel_depth>0));
  634.  
  635.     return pos_object;
  636. }
  637.  
  638. /*
  639.     Perform a few fixes on a menu tree prior to installing it
  640.     (ensure title spacing & items fit into their menus)
  641. */
  642. void fix_menu(OBJECT *root)
  643. {
  644.     short pxy[8];
  645.     short title,mnx=0,mnh,mnw,temp;
  646.     short surround,text;
  647.  
  648.     title=root[root[root[0].ob_head].ob_head].ob_head;
  649.     surround=root[root[0].ob_tail].ob_head;
  650.     
  651.     while(title!=root[root[0].ob_head].ob_head)        /* Fix title spacings (some resource editors don't set them up right) */
  652.     {
  653.         root[title].ob_x=mnx;
  654.         root[surround].ob_x=mnx;
  655.  
  656.         vqt_extent(V_handle,(char*)root[title].ob_spec,pxy);
  657.         mnw=(abs(pxy[2]-pxy[0])+4);
  658.         mnx+=mnw;
  659.         root[title].ob_width=mnw;
  660.         root[title].ob_height=display.c_max_h;
  661.  
  662.         mnw=mnh=0;
  663.         
  664.         for(text=root[surround].ob_head; text!=surround; text=root[text].ob_next)
  665.         {
  666.             vqt_extent(V_handle,(char*)root[text].ob_spec,pxy);
  667.             temp=abs(pxy[2]-pxy[0]);
  668.  
  669.             if (temp>mnw)
  670.                 mnw=temp;
  671.                 
  672.             mnh+=display.c_max_h;
  673.         }
  674.         
  675.         root[surround].ob_width=mnw;
  676.         root[surround].ob_height=mnh;
  677.  
  678.         title=root[title].ob_next;
  679.         surround=root[surround].ob_next;
  680.     }
  681.     
  682.     root[0].ob_width=mnx;
  683.     root[0].ob_height=display.c_max_h;
  684.     root[root[0].ob_head].ob_width=mnx;
  685.     root[root[0].ob_head].ob_height=display.c_max_h;
  686.     root[root[0].ob_tail].ob_width=mnx;
  687.     root[root[0].ob_tail].ob_height=display.c_max_h;
  688. }
  689.